/******************** (C) COPYRIGHT 2018 merafour ********************
* Author             : 冷月追风@merafour.blog.163.com
* Version            : V1.0.0
* Date               : 8/1/2019
* Description        : 设备通讯线程.
********************************************************************************
* merafour.blog.163.com
* merafour@163.com
* github.com/Merafour
*******************************************************************************/
#include "thread_ipmb.h"
#include <QTime>
#include "QiSerial/qiserialport.h"

uint8_t thread_ipmb::_exit = 0;

//thread_ipmb::thread_ipmb(QObject *parent) : QObject(parent)
//{
//    vpx_solt_id = 0;
//    slave_addr=0xEE;
//}

//thread_ipmb::thread_ipmb(QObject *parent, ipmb_cpu_data &_data)  : QObject(parent), _cpu_data(_data)
//{
//    vpx_solt_id = 0;
//    slave_addr=0xEE;
//}

void thread_ipmb::doWork(const QString COM)
{
    qDebug() << "cpu::doWork into ";
    QString port;
    QString str;
    _port = new QiSerialPort();
    qDebug() << "Worker Run Thread : " << QThread::currentThreadId();
    qDebug() << QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd") ;
    //interface = new interface_ipmc(this);
    interface = new interface_ipmc(*_port);
    connect(interface, SIGNAL(sig_progress_update(const QString &, int)), this, SLOT(slots_progress_update(const QString &, int)));
    uint time_now =QDateTime::currentDateTime().toTime_t();
    uint time_start =QDateTime::currentDateTime().toTime_t();
    uint timeout =time_start+30; // 30s 建立连接时间
    port = COM;

    _stop = 0;
    while((0==_exit) && (0==_stop))
    {
        QThread::msleep(50);
        // 30s timeout
        time_now =QDateTime::currentDateTime().toTime_t();
        if(timeout<time_now)
        {
             break;
        }
#if 0
        if (!port.compare("COM") && !port.compare("APM") && !port.compare("ACM") && !port.compare("usb"))
            continue;
#endif
        str = " Watting connect " + port + "sec:" + QString::number(time_now-time_start);
        emit sig_progress_update(str, QiMSGSync::SingalCode::MSG);
        if(0!=_port->OpenPortDefault(port)) continue;
        //connect(_port, &user_port::errorOccurred, _port, &user_port::errorOccurred_slots);
        // 同步,获取信息
        if(0!=interface->identify())
        {
            emit sig_progress_update("SYNC FAIL!", QiMSGSync::SingalCode::MSG);
        }
        else
        {
            loop();
        }
        if(0!=_port->stop()) break;
        interface->__reboot();
        QThread::msleep(500);
        //disconnect(_port, &user_port::errorOccurred, _port, &user_port::errorOccurred_slots);
        _port->close();
    }
    emit sig_progress_update(COM, QiMSGSync::SingalCode::DOWN);
    delete interface;
    delete _port;
    uint time_end =QDateTime::currentDateTime().toTime_t();
    uint _time = time_end-time_start;
    emit sig_progress_update(" Time:"+QString::number(_time)+" s", QiMSGSync::SingalCode::TIME);
    if(1==_exit) exit(0);
}

void thread_ipmb::loop()
{
//    const cJSON* root =  _storage->get_root();
//    char* json_str;

    uint8_t tx_index=0;
    uint8_t list_row=0;
    uint8_t slave_addr=0;
    uint32_t count=0;
    //search_ipmc();
    _search_flag = 1;
    list_row = 0;
    // 读取数据
    while((0==_exit) && (0==_stop))
    {
        if(1==_search_flag) // 搜索总线上的设备
        {
            _search_flag = 0;
            _ipmc_protocol.list_clear_addr();
            search_ipmc();
            continue;
        }
        QThread::msleep(10);
        //slave_addr=_ipmc_protocol.get_slave_addr(vpx_solt_id);
        slave_addr=_ipmc_protocol.list_get_addr(list_row);
        if(0x00==slave_addr)
        {
            _search_flag = 1;
            continue;
        }
        master_test(slave_addr, tx_index);
        if(0!=_port->stop())
        {
            _stop=1;
            emit sig_progress_update("通讯错误", QiMSGSync::SingalCode::MSG);
        }
        tx_index++;     // 循环获取单个设备数据
        if(tx_index>18) // 遍历设备列表
        {
            slave_addr = _ipmc_protocol.list_get_addr(list_row);
            this->storage_data(slave_addr, count);
            count++;
            tx_index=0;
            list_row++;
            if(list_row>=_ipmc_protocol.list_get_addr_max())
            {
                list_row=0;
            }
        }
    }
    //_storage->save();
    //json_str = cJSON_Print(root);
    //json_str = cJSON_PrintUnformatted(root);
    //QiTranslator::savecJSON(path, json_str);
    //qDebug("json[%3d]: %s", count, json_str);

    //if(nullptr!=root) cJSON_Delete(root);
    //if(nullptr!=json_str) free(json_str);
}
/**
IPMB 为 IIC 多主通信,该函数主要测试用,用户从其他板子获取数据,即充当 CPU 的角色
*/
void thread_ipmb::master_test(const uint8_t slave_addr, const uint8_t _cmd)
{
    //static uint8_t tx_index=0;
    struct ipmi_protocol pack;
    struct ipmi_protocol pack_ipmc;
    int ret = -1;
    uint8_t buffer[128];
    uint8_t _lenght=0;
    memset(&pack, 0, sizeof (struct ipmi_protocol));
    memset(&pack_ipmc, 0, sizeof (struct ipmi_protocol));
    // 获取一个数据包
    switch(_cmd)
    {
        case 0: // 主机获取电源板的自检状态（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFC, 0x00); // data=0x00
            break;
        case 1: // 主机获取电源板的温度（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFD, 0x00); // data=0x00, not ID
            break;
        case 17: // 主机获取 MCU 温度（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFD, 0x10); // data=0x00, not ID
            break;
        case 2: // 主机获取电源板的电流（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x09); // ID=0x00, not support
            break;
        case 3: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x09); // ID=0x09, 12V main 输出电流
            break;
        case 4: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x0A); // ID=0x0A, 12V aux 输出电流
            break;
        case 5: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x0B); // ID=0x0B, 5V main 输出电流
            break;
        case 6: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x0C); // ID=0x0C, 5V aux 输出电流
            break;
        case 7: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x0D); // ID=0x0D, 3.3V main 输出电流
            break;
        case 8: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFF, 0x0E); // ID=0x0E, 3.3V aux 输出电流
            break;
        case 9: // 主机获取电源板的电压（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x02); // ID=0x00, not support
            break;
        case 10: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x02); // ID=0x02, 28VDC
            break;
        case 11: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x03); // ID=0x02, 12VDC_MAIN
            break;
        case 12: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x04); // ID=0x02, 12VDC_AUX
            break;
        case 18: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x11); // ID=0x02, -12VDC_AUX
            break;
        case 13: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x05); // ID=0x02, 5VDC_MAIN
            break;
        case 14: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x06); // ID=0x02, 5VDC_AUX
            break;
        case 15: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x07); // ID=0x02, 3V3DC_MAIN
            break;
        case 16: //
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFE, 0x08); // ID=0x02, 3V3DC_AUX
            break;
        default: // 主机获取电源板的自检状态（CPU→IPMC）
            _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFC, 0x00); // data=0x00
            break;
    }
    // 发送数据
    _lenght = _ipmc_protocol.encode_send_ipmc(&pack, buffer, sizeof(buffer));
    ret = interface->msg_from_pc(pack.rsSA, interface_ipmc::IPMC::MSG2DEV, QiMSGSync::EOC, buffer, _lenght);
    if(0==ret)
    {
        uint8_t name[16];
        // recv
        ret = interface->msg_send2_pc(interface_ipmc::IPMC::MSG2PC, QiMSGSync::OK, QiMSGSync::EOC, \
                                name, buffer, sizeof (buffer));
        _lenght = static_cast<uint8_t>(ret);
        if(ret>0)
        {
            // decode
            ret = _ipmc_protocol.decode_send_cpu(&pack_ipmc, _ipmc_protocol.get_ipmb_addr(), buffer, _lenght);
            //qDebug("decode_send_cpu: %d", ret);
            if(0==ret)
            {
                ret = _ipmc_protocol.decode_item(&pack_ipmc);
                if(0==ret)
                {
                    // 上报数据
                    emit sig_progress_update(QString::number(pack_ipmc.rsSA), QiMSGSync::SingalCode::REPO);
                    emit sig_progress_update("接收到数据 ADDR:0x"+QString("%1").arg(pack_ipmc.rsSA, 2, 16, QLatin1Char('0')) + \
                                             " NetFn:0x"+QString("%1").arg(pack_ipmc.NetFn, 2, 16, QLatin1Char('0')), QiMSGSync::SingalCode::MSG);
                }
                else
                {
                    emit sig_progress_update("接收到编码错误数据", QiMSGSync::SingalCode::MSG);
                }
            }
        }
    }
}
// 搜索 IPMC 设备
void thread_ipmb::search_ipmc()
{
    uint8_t _index=0;
    struct ipmi_protocol pack;
    struct ipmi_protocol pack_ipmc;
    uint8_t slave_addr;
    int ret = -1;
    uint8_t buffer[128];
    uint8_t _lenght=0;
    memset(&pack, 0, sizeof (struct ipmi_protocol));
    memset(&pack_ipmc, 0, sizeof (struct ipmi_protocol));

    // 使用自检命令搜索设备
    for (_index=0; _index<32; _index++)
    {
        QThread::msleep(50);
        if(0!=_port->stop())
        {
            return;
        }
        if((0!=_exit) || (0!=_stop)) return;
        slave_addr = _ipmc_protocol.get_slave_addr(_index);
        //slave_addr = _ipmc_protocol.get_slave_addr(0);
        //qDebug("search slave_addr: 0x%02X _index:%d", slave_addr, _index);
        //emit sig_progress_update("搜索设备 ADDR:0x"+QString("%1").arg(slave_addr, 2, 16, QLatin1Char('0')) + " ...", QiMSGSync::SingalCode::MSG);
        // 主机获取电源板的自检状态（CPU→IPMC）
        _ipmc_protocol.pack_send_ipmc(&pack, slave_addr, 0x30<<2, 0xFC, 0x00); // data=0x00
        emit sig_progress_update("搜索设备 ADDR:0x"+QString("%1").arg(pack.rsSA, 2, 16, QLatin1Char('0')) + " ...", QiMSGSync::SingalCode::MSG);
        // 发送数据
        _lenght = _ipmc_protocol.encode_send_ipmc(&pack, buffer, sizeof(buffer));
        ret = interface->msg_from_pc(pack.rsSA, interface_ipmc::IPMC::MSG2DEV, QiMSGSync::EOC, buffer, _lenght);
        if(0!=ret)  // 重发
        {
            QThread::msleep(50);
            ret = interface->msg_from_pc(pack.rsSA, interface_ipmc::IPMC::MSG2DEV, QiMSGSync::EOC, buffer, _lenght);
            if(0!=ret)  // 重发
            {
                QThread::msleep(50);
                ret = interface->msg_from_pc(pack.rsSA, interface_ipmc::IPMC::MSG2DEV, QiMSGSync::EOC, buffer, _lenght);
            }
        }
        if(0==ret)
        {
            uint8_t name[16];
            //QThread::msleep(100);
            // recv
            ret = interface->msg_send2_pc(interface_ipmc::IPMC::MSG2PC, QiMSGSync::OK, QiMSGSync::EOC, \
                                    name, buffer, sizeof (buffer));
            _lenght = static_cast<uint8_t>(ret);
            if(ret>0)
            {
                // decode
                ret = _ipmc_protocol.decode_send_cpu(&pack_ipmc, _ipmc_protocol.get_ipmb_addr(), buffer, _lenght);
                //qDebug("decode_send_cpu: %d", ret);
                if(0==ret)
                {
                    ret = _ipmc_protocol.decode_item(&pack_ipmc);
                    if(0==ret)
                    {
                        // 上报数据
                        emit sig_progress_update(QString::number(pack_ipmc.rsSA), QiMSGSync::SingalCode::REPO);
                     }
                }
            }
        }
    }
}

void thread_ipmb::storage_data(const uint8_t slave_addr, const uint32_t count)
{
//    const cJSON* root =  _storage->get_root();
//    char* json_str;
    struct ipmc_data _data;
    double numbers[4];
    get_ipmc_data_faddr(_data, slave_addr);
    // 存储数据
    QString item = "board_"+QString("%1").arg(slave_addr, 2, 16, QLatin1Char('0'))+"_"+QString::number(count);
    //_storage->add_item(item.toLocal8Bit().data());
    _storage->add_branch_in_item(item.toLocal8Bit().data());
    //_storage->add_branch_in_item("board");
    _storage->add_object("Des",  _ipmc_protocol.get_device_type(_data.dev_type));
#if 0
    _storage->add_number("solt_id", _data.solt_id);
    _storage->add_number("type", _data.dev_type);
    _storage->add_number("status", _data.status);
    _storage->add_number("code", _data.code);
#else
    _storage->add_object("arg", "solt_id, type, status, code");
    numbers[0] = _data.solt_id;
    numbers[1] = _data.dev_type;
    numbers[2] = _data.status;
    numbers[3] = _data.code;
    _storage->add_array("value", numbers, 4);
#endif
    //_storage->brack_last_branch();
    //_storage->add_branch_in_item("data");
    //_storage->add_object("data", "data");
    for(int i=0; i<20; i++)
    {
        _storage->add_branch_in_item(("item"+QString::number(i)).toLocal8Bit().data());
        _storage->add_object("Des",  _ipmc_protocol.get_item_info(_data.item[i].id));
#if 0
        _storage->add_number("id", _data.item[i].id);
        _storage->add_number("value", static_cast<double>(_data.item[i].value));
        _storage->add_number("code", _data.item[i].code);
#else
    _storage->add_object("arg", "id, value, code");
    numbers[0] = _data.item[i].id;
    numbers[1] = static_cast<double>(_data.item[i].value);
    numbers[2] = _data.item[i].code;
    _storage->add_array("value", numbers, 3);
#endif
        _storage->brack_last_branch();
    }
    //_storage->brack_last_branch();
    _storage->brack_last_branch();
    _storage->save();
//    json_str = cJSON_Print(root);
//    //json_str = cJSON_PrintUnformatted(root);
//    //QiTranslator::savecJSON("ipmb.txt", json_str);
//    //qDebug("json[%3d]: %s", count, json_str);

//    //if(nullptr!=root) cJSON_Delete(root);
//    if(nullptr!=json_str) free(json_str);
}

